package com.example.synatx.stream;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * Collector<T,A,R>
 *     T : 流中药手机的项目的泛型
 *     A : 累加器的类型,累加器是在收集过程中用于累积部分结果的对象
 *     R : 收集操作得到的对象(通常但不一定是集合)的类型
 * @param <T>
 */
public class MyCollector<T> implements Collector<T, List<T>,List<T>> {
    /**
     * 建立新结果的容器,supplier方法返回一个结果为空的Supplier,也就是一个无参数函数,在调用它的时候创建一个空的累加器示例,供数据收集过程使用.
     * @return
     */
    @Override
    public Supplier<List<T>> supplier() {
        Supplier<List<T>> t = ArrayList::new;
        return ()-> new ArrayList<>();
    }

    /**
     * 将元素添加到结果容器, accumulator方法会返回执行归约操作的函数.当遍历到流的第n个元素时,这个函数执行时会有两个参数,保存归约
     * 结果的累加器(已经保存了前n-1个项目)还有第n个元素本身.
     * 该函数将返回void,因为累加器是原位更新,即函数的执行改变了它的内部状态以体现遍历的元素结果
     * @return
     */
    @Override
    public BiConsumer<List<T>, T> accumulator() {
        return List::add;
        //return (list,item) -> list.add(item);
    }

    /**
     * 合并两个结果容器
     * combiner方法会返回一个供归约操作使用的函数,它定义了对流的各个子部分进行并行处理时,各个子部分归约所得的累加器要如何合并
     * @return
     */
    @Override
    public BinaryOperator<List<T>> combiner() {
        return (list1,list2)-> {list1.addAll(list2);
                return list1;
        };
    }

    /**
     * 在遍历完流后,finisher方法必须在累积过程的最后要调用的一个函数,以便将累加器对象转换为整个集合操作的最终结果.
     *
     * @return
     */
    @Override
    public Function<List<T>, List<T>> finisher() {
        return Function.identity();
    }


    /**
     * 会返回一个不可变的Characteristics集合.它定义了收集器的行为--尤其是关于流是否可以并行归约,以及可以使用那些优化提示.
     * Characteristics 包含三个项目的枚举值
     *   * CONCURRENT - 归约结果不受流中项目的遍历和累积顺序
     *   * UNORDERED - accumulator函数可以从多线程同时调用,且该收集器可以并行归约流.如果收集器没有标记为UNORDERD,那他仅在用于无序数据源时才可以并行归约
     *   * IDENTITY_FINISH - 这表明完成器方法返回的函数式一个恒等函数,可以跳过.这种情况下,累加器对象将会直接用作归约过程的最终结果.这也意味着,将累加器A不加检查的转换成结果R是安全的
     * @return
     */
    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.CONCURRENT));
    }
}
